package com.hoshiicloud.auth.service.impl;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hoshiicloud.auth.feign.UserFeignService;
import com.hoshiicloud.auth.feign.VeriCenterFeignService;
import com.hoshiicloud.auth.service.CompanyUserService;
import com.hoshiicloud.auth.service.UserService;
import com.hoshiicloud.auth.vo.LoginVO;
import com.hoshiicloud.auth.vo.TokenUsersVO;
import com.hoshiicloud.common.constant.TokenUserFieldEnum;
import com.hoshiicloud.common.constant.UserTypeEnum;
import com.hoshiicloud.common.exception.CommonError;
import com.hoshiicloud.common.exception.ServiceException;
import com.hoshiicloud.common.rpc.Response;
import com.hoshiicloud.common.utils.token.JWTUtil;
import com.hoshiicloud.user.dto.userCenter.MemberDto;
import com.hoshiicloud.user.entity.company.ComUsers;
import com.hoshiicloud.user.entity.company.Company;
import com.hoshiicloud.user.entity.company.Member;
import com.hoshiicloud.user.param.company.CompanyPageParam;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
//TODO jwt签名密钥规则修改

/**
 * @program: hoshiicloud-biz
 * @description: 租户会员服务接口实现类
 * @author: Mr.wu
 * @create: 2019-08-22 17:58
 **/
@Slf4j
@Service
@AllArgsConstructor
public class CompanyUserServiceImpl implements CompanyUserService {

    private final VeriCenterFeignService veriCenterFeignService;

    private final UserFeignService userFeignService;

    private final RedisTemplate<String, Object> redisTemplate;

    private final UserService userService;


    @Override
    public Response memberPasswordLogin(String privateDomain, String userName, String password) {
        Long companyId = null;
        //增加二级域名登录
        if (StringUtils.isNotBlank(privateDomain)) {
            CompanyPageParam companyPageParam = new CompanyPageParam();
            companyPageParam.setPrivateDomain(privateDomain);
            Response<Page<Company>> tresult = userFeignService.getCompanyList(companyPageParam);
            if (tresult.isSuccess()) {
                List<Company> companyList = tresult.getData().getRecords();
                if (CollectionUtils.isEmpty(companyList)) {
                    return Response.failed("用户不存在");
                }
                Company company = companyList.get(0);
                companyId = company.getId();
            } else {
                throw new ServiceException("分页失败");
            }

        } else if (companyId == null && StringUtils.isBlank(privateDomain)) {
            return Response.failed("用户不存在");
        }

        Member member = new Member();
        member.setCompanyId(companyId);
        //用户名为手机号码
        member.setPhone(userName);
        //TODO 密码加密
        member.setPassword(password);
        Response result = userFeignService.getMemberList(member);
        if (result.isSuccess()) {
            List<Member> memberList = (List<Member>) result.getData();
            if (memberList.size() == 1) {
                member = memberList.get(0);
                LoginVO loginVO = new LoginVO();
                loginVO.setToken(getMemberRefreshToken(member.getId(), member.getCompanyId(), member.getId() + member.getPassword()));
                return Response.data(loginVO);
            } else if (CollectionUtils.isEmpty(memberList)) {
                return Response.failed("用户名或密码错误");
            } else {
                log.error("用户:" + userName + "出现帐号重复");
                return Response.failed("用户重复!");
            }

        } else {
            return result;
        }
    }

    @Override
    public Response memberSmsLogin(Long companyId, String privateDomain, String phone, String msgId, String code) {
        Response result = veriCenterFeignService.checkCode(msgId, code);
        if (result.isSuccess()) {
            //增加二级域名登录
            if (companyId == null && StringUtils.isNotBlank(privateDomain)) {
                CompanyPageParam companyPageParam = new CompanyPageParam();
                companyPageParam.setPrivateDomain(privateDomain);
                Response<Page<Company>> tresult = userFeignService.getCompanyList(companyPageParam);
                List<Company> companyList = tresult.getData().getRecords();
                if (CollectionUtils.isEmpty(companyList)) {
                    return Response.failed("用户不存在");
                }
                Company company = companyList.get(0);
                companyId = company.getId();
            } else if (companyId == null && StringUtils.isBlank(privateDomain)) {
                return Response.failed("用户不存在");
            }

            //获取租户会员id,签发MemberToken
            result = userFeignService.getMemberByMobile(companyId, phone);
            if (result.isSuccess()) {
                MemberDto member = (MemberDto) result.getData();
                LoginVO loginVO = new LoginVO();
                loginVO.setToken(getMemberRefreshToken(member.getId(), member.getCompanyId(), member.getId() + member.getPassword()));
                return Response.data(loginVO);
            } else {
                return result;
            }
        } else {
            return result;
        }
    }


    @Override
    public String getMemberRefreshToken(Long memberId, Long companyId, String secret) {
        String loginKey = "memberLogin" + ":" + memberId + ":refreshToken:" + System.currentTimeMillis();
        String token = JWTUtil.signMemberRefreshToken(memberId, companyId, loginKey, secret);
        redisTemplate.opsForValue().set(loginKey, token, 1, TimeUnit.DAYS);
        return token;
    }

    @Override
    public Response<LoginVO> getMemberAccessToken(String memberRefreshToken) {
        //验证token有效性
        DecodedJWT jwt = JWTUtil.getDecodedJWT(memberRefreshToken);
        Long memberId = jwt.getClaim(TokenUserFieldEnum.MEMBER_ID.getName()).asLong();
        Long companyId = jwt.getClaim(TokenUserFieldEnum.COMPANY_ID.getName()).asLong();
        String loginKey = jwt.getClaim(TokenUserFieldEnum.LOGIN_KEY.getName()).asString();
        String redisMemberRefreshToken = (String) redisTemplate.opsForValue().get(loginKey);
        if (!memberRefreshToken.equals(redisMemberRefreshToken)) {
            return Response.failed(CommonError.unauthorizedError());
        }
        //根据token寻找租户用户并签发accessToken
        Member member = new Member();
        member.setId(memberId);
        Response result = userFeignService.getMemberList(member);
        if (result.isSuccess()) {
            List<Member> memberList = (List<Member>) result.getData();
            if (memberList.size() == 1) {
                member = memberList.get(0);
                LoginVO loginVO = new LoginVO();
                loginVO.setAccessToken(
                        JWTUtil.signMemberAccessToken(member.getId(), member.getCompanyId(), member.getId() + member.getPassword()));
                //保存令牌相关信息到redis
                //租户会员访问令牌非后台管理系统，因此不保存权限信息等，仅保存令牌
                String accessTokenKey = "memberLogin:" + member.getId() + ":accessToken:" + System.currentTimeMillis();
                TokenUsersVO tokenUsersVO = new TokenUsersVO();
                tokenUsersVO.setUserId(memberId);
                tokenUsersVO.setUserType(UserTypeEnum.MEMBER.getUserType());
                tokenUsersVO.setToken(loginVO.getAccessToken());
                redisTemplate.opsForValue()
                        .set(loginVO.getAccessToken(), tokenUsersVO, JWTUtil.ACCESS_TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);
                return Response.data(loginVO);
            } else if (CollectionUtils.isEmpty(memberList)) {
                return Response.failed("用户不存在");
            } else {
                return result;
            }
        } else {
            return result;
        }
    }

    @Override
    public Response getPlatformUserAccessToken(Long platformId, String memberRefreshToken) {
        //验证token有效性
        DecodedJWT jwt = JWTUtil.getDecodedJWT(memberRefreshToken);
        Long memberId = jwt.getClaim(TokenUserFieldEnum.MEMBER_ID.getName()).asLong();
        Long companyId = jwt.getClaim(TokenUserFieldEnum.COMPANY_ID.getName()).asLong();
        String loginKey = jwt.getClaim(TokenUserFieldEnum.LOGIN_KEY.getName()).asString();
        String redisMemberRefreshToken = (String) redisTemplate.opsForValue().get(loginKey);
        if (!memberRefreshToken.equals(redisMemberRefreshToken)) {
            return Response.failed(CommonError.unauthorizedError());
        }
        //根据token寻找平台用户并签发token
        Map<String, Object> map = new HashMap<>(16);
        map.put("memberId", memberId);
        map.put("platformId", platformId);
        Response<TokenUsersVO> result = userFeignService.getPlatformMemberUser(map);
        if (result.isSuccess()) {
            TokenUsersVO tokenUsersVO = result.getData();
            String secret = tokenUsersVO.getUserId() + tokenUsersVO.getPassword();
            String token = JWTUtil.signPlatformAccessToken(memberId, companyId, platformId, secret);
            //保存令牌相关权限信息到redis
            String accessTokenKey = "platformUserLogin:" + tokenUsersVO.getUserId() + ":" + System.currentTimeMillis();
            redisTemplate.opsForValue().set(token, tokenUsersVO, JWTUtil.ACCESS_TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);
            LoginVO loginVO = new LoginVO();
            loginVO.setAccessToken(token);
            return Response.data(loginVO);
        } else {
            return result;
        }
    }

    @Override
    public Response getStoreUserAccessToken(Long storeId, String memberRefreshToken) {
        //验证token有效性
        DecodedJWT jwt = JWTUtil.getDecodedJWT(memberRefreshToken);
        Long memberId = jwt.getClaim(TokenUserFieldEnum.MEMBER_ID.getName()).asLong();
        Long companyId = jwt.getClaim(TokenUserFieldEnum.COMPANY_ID.getName()).asLong();
        String loginKey = jwt.getClaim(TokenUserFieldEnum.LOGIN_KEY.getName()).asString();
        String redisMemberRefreshToken = (String) redisTemplate.opsForValue().get(loginKey);
        if (!memberRefreshToken.equals(redisMemberRefreshToken)) {
            return Response.failed(CommonError.unauthorizedError());
        }
        //根据token寻找平台用户并签发token
        Map<String, Object> map = new HashMap<>();
        map.put("memberId", memberId);
        map.put("storeId", storeId);
        Response<TokenUsersVO> result = userFeignService.getStoreMemberUser(map);
        if (result.isSuccess()) {
            TokenUsersVO tokenUsersVO = result.getData();
            String secret = tokenUsersVO.getUserId() + tokenUsersVO.getPassword();
            String token = JWTUtil.signStoreAccessToken(memberId, companyId, storeId, secret);
            //保存令牌相关权限信息到redis
            String accessTokenKey = "storeUserLogin:" + tokenUsersVO.getUserId() + ":" + System.currentTimeMillis();
            redisTemplate.opsForValue().set(token, tokenUsersVO, JWTUtil.ACCESS_TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);
            LoginVO loginVO = new LoginVO();
            loginVO.setAccessToken(token);
            return Response.data(loginVO);
        } else {
            return result;
        }

    }

    /**
     * 租户内部管理系统
     *
     * @param privateDomain 二级域名
     * @param userName      账户
     * @param password      密码
     * @return LoginVO
     * @see #getComUsersRefreshToken(String, Long, Long, String) 签发登录Token
     */
    @Override
    public Response<LoginVO> companyUserLogin(String privateDomain, String userName, String password) {
        Response result = userFeignService.getCompanyUserList(privateDomain, userName, password);
        if (result.isSuccess()) {
            List<ComUsers> comUsersList = (List<ComUsers>) result.getData();
            if (comUsersList.size() == 1) {
                LoginVO loginVO = new LoginVO();
                ComUsers companyUser = comUsersList.get(0);
                String comUsersRefreshToken = this.getComUsersRefreshToken(privateDomain, companyUser.getId(), companyUser.getCompanyId(),
                        companyUser.getId() + companyUser.getPassword());
                loginVO.setToken(comUsersRefreshToken);
                return Response.data(loginVO);
            } else if (CollectionUtils.isEmpty(comUsersList)) {
                return Response.failed("用户名或密码错误");
            } else {
                log.error("用户:" + userName + "出现帐号重复");
                return Response.failed("用户重复!");
            }
        } else {
            return result;
        }
    }

    /**
     * comUsers 切换账号使用
     *
     * @param comUsersRefreshToken comUsersRefreshToken
     * @return LoginVo
     */
    @Override
    public Response<LoginVO> companyUserAccessToken(String comUsersRefreshToken) {
        // 验证Token有效性
        DecodedJWT decodedJWT = JWTUtil.getDecodedJWT(comUsersRefreshToken);
        // String privateDomain = decodedJWT.getClaim(TokenUserFieldEnum.PRIVATE_DOMAIN.getName()).asString();
        Long userId = decodedJWT.getClaim(TokenUserFieldEnum.USER_ID.getName()).asLong();
        Long companyId = decodedJWT.getClaim(TokenUserFieldEnum.COMPANY_ID.getName()).asLong();
        String loginKey = decodedJWT.getClaim(TokenUserFieldEnum.LOGIN_KEY.getName()).asString();
        String redisComUsersRefreshToken = redisTemplate.opsForValue().get(loginKey).toString();
        if (!comUsersRefreshToken.equals(redisComUsersRefreshToken)) {
            return Response.failed(CommonError.unauthorizedError());
        }
        ComUsers comUsers = ComUsers.builder()
                .id(userId)
                .companyId(companyId)
                .build();
        Response result = userFeignService.getCompanyUserListByModel(comUsers);
        if (result.isSuccess()) {
            ComUsers comUsersQuery = (ComUsers) result.getData();
            if (comUsersQuery == null) {
                return Response.failed("用户不存在");
            }
            LoginVO loginVO = new LoginVO();
            loginVO.setAccessToken(
                    JWTUtil.signMemberAccessToken(comUsersQuery.getId(), comUsersQuery.getCompanyId(),
                            comUsersQuery.getId() + comUsersQuery.getPassword()));
            //保存令牌相关信息到redis
            //租户会员访问令牌非后台管理系统，因此不保存权限信息等，仅保存令牌
            TokenUsersVO tokenUsersVO = new TokenUsersVO();
            tokenUsersVO.setUserId(comUsers.getId());
            tokenUsersVO.setUserType(UserTypeEnum.COMPANY.getUserType());
            tokenUsersVO.setToken(loginVO.getAccessToken());
            redisTemplate.opsForValue()
                    .set(loginVO.getAccessToken(), tokenUsersVO, JWTUtil.ACCESS_TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);
            return Response.data(loginVO);
        } else {
            return result;
        }
    }

    /**
     * 签发租户内部管理系统Token
     *
     * @param userId    userId
     * @param companyId companyId
     * @param secret    secret
     * @return Token(String)
     */
    private String getComUsersRefreshToken(String privateDomain, Long userId, Long companyId, String secret) {
        String loginKey = "companyLogin" + ":" + privateDomain + ":" + userId + ":refreshToken:" + System.currentTimeMillis();
        String token = JWTUtil.signCompanyRefreshToken(privateDomain, userId, companyId, loginKey, secret);
        redisTemplate.opsForValue().set(loginKey, token, 1, TimeUnit.DAYS);
        return token;
    }
}
